package cn.iocoder.yudao.module.resource.api;

import cn.hutool.dfa.WordTree;
import cn.iocoder.yudao.framework.common.util.cache.CacheUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.resource.api.model.AudioCommandDTO;
import cn.iocoder.yudao.module.resource.convert.audio.command.AudioCommandConvert;
import cn.iocoder.yudao.module.resource.events.RefreshAudioCommandEvent;
import cn.iocoder.yudao.module.resource.service.audiocommand.AudioCommandService;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service
@Slf4j
public class AudioCommandApiImpl implements IAudioCommandApi {
    private WordTree tree;

    @Resource
    private AudioCommandService audioCommandService;

    @PostConstruct
    public void init() {
        handleRefreshAudioCommandEvent(null);
    }

    @EventListener
    public void handleRefreshAudioCommandEvent(RefreshAudioCommandEvent event) {
        word2CommandMap.refresh(getClass().getName());
    }

    @Getter
    private final LoadingCache<String, Map<String, AudioCommandDTO>> word2CommandMap = CacheUtils.buildCache(Duration.ofMinutes(60L),
            new CacheLoader<>() {

                @Override
                public Map<String, AudioCommandDTO> load(String id) {
                    final Map<String, AudioCommandDTO> res = new HashMap<>();
                    List<AudioCommandDTO> commandList = getAvailableAudioCommandList();
                    for (AudioCommandDTO command : commandList) {
                        if (StringUtils.isNotBlank(command.getKeyword())) {
                            String[] split = command.getKeyword().split("\\|");
                            for (String s : split) {
                                res.put(StringUtils.trim(s), command);
                            }
                        }
                    }

                    // https://doc.hutool.cn/pages/dfa/#_1-%E6%9E%84%E5%BB%BA%E5%85%B3%E9%94%AE%E8%AF%8D%E6%A0%91
                    // 查询语音指令表中所有的关键字，并添加到 tree 中
                    final WordTree tree = new WordTree();
                    for (String word : res.keySet()) {
                        tree.addWord(word);
                    }
                    AudioCommandApiImpl.this.tree = tree;

                    log.info("刷新AudioCommand缓存");
                    return res;
                }
            });

    @Override
    public Map<String, AudioCommandDTO> getWord2Command() {
        return getWord2CommandMap().getUnchecked(getClass().getName());
    }

    @Override
    public AudioCommandDTO getAudioCommandByOperateType(String sensorType, String operateType) {
        return BeanUtils.toBean(audioCommandService.getAudioCommandByOperateType(sensorType, operateType), AudioCommandDTO.class);
    }

    @Override
    public AudioCommandDTO getAudioCommandByTitle(String title) {
        return AudioCommandConvert.INSTANCE.convert(audioCommandService.getAudioCommandByTitle(title));
    }

    @Override
    public List<AudioCommandDTO> getAvailableAudioCommandList() {
        return BeanUtils.toBean(audioCommandService.getAvailableAudioCommandList(), AudioCommandDTO.class);
    }

    @Override
    public Map<String, AudioCommandDTO> getAudioCommandOperateTypeMap() {
        final Map<String, AudioCommandDTO> res = new HashMap<>();

        final List<AudioCommandDTO> commandList = getAvailableAudioCommandList();
        for (AudioCommandDTO command : commandList) {
            final String key = command.getSensorType() + command.getOperateType();
            res.put(key, command);
        }
        return res;
    }

    @Override
    public List<String> matchedWords(String text) {
        getWord2Command();
        final List<String> matchedWords = tree.matchAll(text, -1, true, true);
        return matchedWords;
    }


}
